import customStorage from '@/hooks/useStorage';
import { CacheEnum } from '@/enum/cacheEnum';
import { ref } from 'vue';
import type { MenuType } from '@/types/menu';
import { type RouteLocationNormalized, type RouteRecordRaw } from 'vue-router';
import { RouterEnum } from '@/enum/routerEnum';
import systomRouter from '@/router';
import userStroe from '@/plugins/pinia/stores/user';
import { util } from '@/utils';
import { PermissionsEnum } from '@/enum';

class Menu {
  public menus = ref<MenuType.Menu[]>([]);
  public history = ref<MenuType.Menu[]>([]);
  public close = ref(false);

  constructor() {
    this.init();
  }

  public async init() {
    await systomRouter.isReady();
    this.menus.value = this.getMenus();
    this.history.value = this.getHistoryMenus();
  }

  /**
   * 从本地存储获取历史菜单
   */
  private getHistoryMenus() {
    const historyStorage = customStorage.getItem<MenuType.Menu[]>(CacheEnum.HISTORY_MENU) ?? [];
    const menus = this.getAdminMenus();
    const paths = this.collectPaths(menus);

    // 过滤掉当前路由表中没有的菜单
    return historyStorage.filter((menu) => {
      return paths.includes(menu.link);
    });
  }

  /**
   * 收集所有路径
   * @param menus
   * @returns
   */
  private collectPaths(menus: RouteRecordRaw[]): string[] {
    const paths: string[] = [];

    // 递归函数，用于遍历菜单并收集路径
    const recursion = (menus: RouteRecordRaw[]) => {
      menus.forEach((menu) => {
        menu?.path && paths.push(menu.path);
        if (menu.children && menu.children.length > 0) {
          recursion(menu.children);
        }
      });
    };
    recursion(menus);
    return paths;
  }

  /**
   * 切换菜单栏
   */
  public toggleState() {
    this.close.value = !this.close.value;
  }

  /**
   * 移除历史路由
   */
  public removeHistoryMenu(menu: MenuType.Menu) {
    const index = this.history.value.findIndex((item) => item.link === menu.link);
    this.history.value.splice(index, 1);
    customStorage.setItem(CacheEnum.HISTORY_MENU, this.history);
  }

  /**
   * 添加历史路由
   */
  public addHistoryMenu(route: RouteLocationNormalized) {
    if (!route.meta.menu) return;
    const menu: MenuType.Menu = {
      ...route.meta?.menu,
      link: route.path,
    };

    // 已有就不再添加
    const isHas = this.history.value.some((menu) => {
      return menu.link === route.path;
    });
    !isHas && this.history.value.unshift(menu);
    if (this.history.value.length > 10) {
      this.history.value.pop();
    }

    // 缓存历史记录
    customStorage.setItem(CacheEnum.HISTORY_MENU, this.history.value);
  }

  /**
   * 获取管理后台路由信息
   */
  private getAdminMenus() {
    // 获取管理后台路由信息
    const [adminRoute] = systomRouter.getRoutes().filter((route) => route.name === RouterEnum.ADMIN);

    // 只保留：元信息有菜单数据 且 组件或子路由必须存在一个
    const fn = (routes: RouteRecordRaw[]): RouteRecordRaw[] => {
      return routes.filter((route) => {
        if (route.children?.length) {
          route.children = fn(route.children);
        }
        return route.meta?.menu && (route.component || route.children?.length);
      });
    };
    return fn(adminRoute?.children || []);
  }

  /**
   * 根据路由获取菜单
   */
  private getMenus() {
    let menus = this.getAdminMenus();

    // 递归处理组合菜单信息
    const menusMap = (menus: RouteRecordRaw[]) => {
      return menus.map((route) => {
        const menu: MenuType.Menu = Object.assign({ link: route.path }, route.meta?.menu);
        if (route.children?.length) {
          menu.children = menusMap(route.children);
        }
        return menu;
      });
    };

    // 获取用户权限
    const permissions = userStroe().userInfo?.permissions || [];

    // 超级管理员拥有所有权限
    if (permissions.includes(PermissionsEnum.SUPER_ADMIN)) {
      return menusMap(menus);
    }

    // 过滤掉没有权限的菜单
    const fn = (routes: RouteRecordRaw[]) => {
      return routes.filter((route) => {
        if (route.children?.length) {
          route.children = fn(route.children);
        }

        // 路由元信息中，没有permissions则无需鉴权
        if (!route.meta?.permissions) return true;
        return util.containsArray(permissions, route.meta.permissions);
      });
    };
    menus = fn(menus);

    return menusMap(menus);
  }
}

export default new Menu();
